﻿using System;
using System.Xml.Linq;

namespace Phoenix.Xna.Framework.Serialization.Markup.Objects
{
    /// <summary>
    /// The intermediary markup object describing a loose coupling, only used on the second dereferencing of a class.
    /// While the first reference to a object instance will be given a standard ClassMarkup; all 
    /// other references to that instance will be given a ReferenceMarkup.  This provides a simple 
    /// decoupling of references so they may be traversed more easily.
    /// </summary> 
    internal class ReferenceMarkup : MarkupObjectBase
    {
        private ClassMarkup _classMarkup;

        /// <summary>
        /// Gets the id used by the ReferenceManager to resolve an instance or ClassMarkup.
        /// </summary>
        public string ReferenceId { get; private set; }

        /// <summary>
        /// Initializes a new instance of the ReferenceMarkup class.
        /// </summary>
        public ReferenceMarkup() { }

        /// <summary>
        /// Initializes a new instance of the ReferenceMarkup class.
        /// </summary>
        /// <param name="classMarkup">The markup to reference.</param>
        public ReferenceMarkup(ClassMarkup classMarkup)
        {
            _classMarkup = classMarkup;
            ReferenceId = classMarkup.ReferenceID;
        }

        /// <summary>
        /// Confirms the XElement is the xml form of an ReferenceMarkup object.
        /// </summary>
        public static bool IsReference(XElement xmlInstance)
        {
            return string.Compare(xmlInstance.Name.ToString(), AttributeIDs.ReferenceXMLName, StringComparison.OrdinalIgnoreCase) == 0;
        }

        #region IMarkupElement Members

        /// <summary>
        /// Serialize the element to XML.
        /// </summary>
        /// <returns>The element markup serialzed as an XElement.</returns>
        public override XElement Serialize()
        {
            XElement element = new XElement(AttributeIDs.ReferenceXMLName);
            element.Add(new XAttribute(AttributeIDs.ElementXMLName, _classMarkup.ReferenceID));
            return element;
        }

        /// <summary>
        /// Deserialize the element from an XElement.
        /// </summary>
        /// <param name="element">The XElement to deserialize this element from.</param>
        public override void Deserialize(XElement element)
        {
            ReferenceId = element.Attribute(AttributeIDs.ElementXMLName).Value;
        }

        #endregion

        #region IMarkupObject Members

        /// <summary>
        /// Gets the object that is defined by this instance.
        /// </summary>
        public override object Instance
        {
            get
            {
                if (_classMarkup != null)
                {
                    return _classMarkup.Instance;
                }

                return null;
            }
        }

        /// <summary>
        /// Gets or sets the System.Type of the defined object.
        /// </summary>
        public override Type ObjectType
        {
            get { return _classMarkup.ObjectType; }
            set { throw new NotImplementedException(); }
        }

        /// <summary>
        /// Convert this MarkupObject in to an object model and sets the Instance.
        /// </summary>
        public override void ConstructInstance()
        {
            _classMarkup = Serializer.ReferenceManager.GetMarkupFromReferenceId(ReferenceId);

            if (_classMarkup.Instance == null)
            {
                _classMarkup.ConstructInstance();
            }
        }

        /// <summary>
        /// Extract the markup information from the specified object.
        /// </summary>
        /// <param name="instance">The instance to extract markup information for.</param>
        public override void ExtractMarkup(object instance)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}